/**
 * 1）方式一类似柯里化方式
 * def foo[T]()(implicit m: Manifest[T])
 * 然后再foo函数中使用 manifest[String] 获得类型
 * @param x
 * @param m
 * @tparam T
 */
def foo[T](x: List[T])(implicit m: Manifest[T]) = {
  println(m)
  // <:< 已经过期
  // Use scala.reflect.runtime.universe.TypeTag for subtype checking instead
  // 建议使用 scala.reflect.runtime.universe.TypeTag 检查取代
  if (m <:< manifest[String])
    println("Hey, this list is full of strings")
  else
    println("Non-stringy list")
}

foo(List("one", "two")) // Hey, this list is full of strings
foo(List(1, 2)) // Non-stringy list
foo(List("one", 2)) // Non-stringy list


import scala.reflect._

/**
 * 2）方式2 [T : ClassTag] 使用 ClassTag 替换
 * 参考这个 https://zhuanlan.zhihu.com/p/69792401
 * @param first
 * @param second
 * @tparam T
 * @return
 */
def makePair[T : ClassTag](first: T, second: T) = {
    val r = new Array[T](2)
    r(0) = first
    r(1) = second
    r
}

val a = makePair(4, 2) // An Array[Int]
a.getClass // In the JVM, [I is an int[] array

val b = makePair("Fred", "Brooks") // An Array[String]
b.getClass // In the JVM, [Ljava.lang.String; is a String[] array

/**
 * getValueFromMap1 可以简写为 getValueFromMap2 方式
 */

def getValueFromMap[T](key:String, dataMap: collection.Map[String, Any]): Option[T] = {
  dataMap.get(key) match { // 这里实际上只会判断 dataMap.get(key) 有没有值，不会判断T类型，因为运行时被擦出了
    case Some(value:T) => Some(value)
    case _ => None
  }
}

// 下面两种方式不仅会判断 dataMap.get(key) 是否为空，还会判断 dataMap.get(key) 得到的类型 E（假设为E）是否和你给的T
// 是同一种类型，如果是的话执行否则就进入 _ => None 的逻辑
def getValueFromMap1[T](key:String, dataMap: collection.Map[String, Any])
                      (implicit t:ClassTag[T]): Option[T] = {
  dataMap.get(key) match {
    case Some(value: T) => Some(value)
    case _ => None
  }
}

def getValueFromMap2[T : ClassTag](key:String, dataMap: collection.Map[String, Any]): Option[T] = {
  dataMap.get(key) match {
    case Some(value: T) => Some(value)
    case _ => None
  }
}

val myMap: collection.Map[String, Any] = Map("Number" -> 1, "Greeting" -> "Hello World")
// 现在这行代码没有问题，我们会得到None
// 会报错，因为给的是Int，实际上是String，转换异常
//val greetingInt: Option[Int] = getValueFromMap[Int]("Greeting", myMap)
// 不报错，给的Int，实际上是String会走None的逻辑，不会报错直接返回None
val greetingInt: Option[Int] = getValueFromMap2[Int]("Greeting", myMap)
// prints None
println("greetingInt is " + greetingInt)
// 没有 ClassCastException 并且返回 None
val somevalue = greetingInt.map((x) => x + 5)
// print None
println(somevalue)